package com.mlh.dp.knapsackProblem;

//最后一块石头的重量II
// 有一堆石头，用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
// 每一回合，从中选出任意两块石头，然后将它们一起粉碎。假设石头的重量分别为 x 和 y，且 x <= y。那么粉碎的可能结果如下：
// 如果 x == y，那么两块石头都会被完全粉碎；
// 如果 x != y，那么重量为 x 的石头将会完全粉碎，而重量为 y 的石头新重量为 y-x。
// 最后，最多只会剩下一块石头。返回此石头 最小的可能重量 。如果没有石头剩下，就返回 0

// 输入：stones = [2,7,4,1,8,1]
// 输出：1
// 解释：
// 组合 2 和 4，得到 2，所以数组转化为 [2,7,1,8,1]，
// 组合 7 和 8，得到 1，所以数组转化为 [2,1,1,1]，
// 组合 2 和 1，得到 1，所以数组转化为 [1,1,1]，
// 组合 1 和 1，得到 0，所以数组转化为 [1]，这就是最优值。

import java.nio.MappedByteBuffer;

public class LastStoneWeightII {
    public static void main(String[] args) {
        int[]stones={2,7,4,1,8,1};
        method3(stones);

    }

    //读题思路
    //题目变成 我有两个包  两个包装石头  石头全部要装完  目的是最后两个包的质量差最小
    //这种思路是对的  但是我只能用暴力递归写出来  没办法变成记忆搜索  算是比较奇怪的解法吧
    //暴力递归
    public int method1(int[] stones) {
        return process(stones,0,0,0);
    }
    public int process(int []stones,int bag1,int bag2,int end){
        if(end==stones.length){
            return Math.abs(bag1-bag2);
        }
        return Math.min(process(stones,bag1+stones[end],bag2,end+1),
                process(stones,bag1,bag2+stones[end],end+1));
    }

    //记忆搜索
    public int method2(int[] stones) {
        //int[]dp=new int[stones.length];
        return process1(stones,0,0);
    }
    public int process1(int []stones,int end,int diff){
        if(end==stones.length){
            return diff;
        }
        return Math.min(Math.abs(process1(stones,end+1,diff+stones[end])),
                Math.abs(process1(stones,end+1,diff-stones[end])));

    }

    //以下是看了题解的
    //看题解是如何转化成01背包问题的
    //转化成01背包问题后就很简单了
    public static int method3(int[]stones){
        int tatol=0;
        for(int temp:stones){
            tatol+=temp;
        }
        int bag=tatol>>1;
        int[][]dp=new int[stones.length][bag+1];
        for(int i=stones[0];i<=bag;i++){
            dp[0][i]=stones[0];
        }
        for(int i=1;i<stones.length;i++){
            for(int j=1;j<=bag;j++){
                if(j>=stones[i]){
                    dp[i][j]=Math.max(dp[i-1][j-stones[i]]+stones[i],dp[i-1][j]);
                }else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        return tatol-2*dp[stones.length-1][bag];
    }

    //优化了一下  降成了1维
    public static int method4(int[]stones){
        int tatol=0;
        for(int temp:stones){
            tatol+=temp;
        }
        int bag=tatol>>1;
        int[]dp=new int[bag+1];
        for(int i=stones[0];i<=bag;i++){
            dp[i]=stones[0];
        }
        for(int i=1;i<stones.length;i++){
            for(int j=bag;j>=0;j--){
                if(j>=stones[i]){
                    dp[j]=Math.max(dp[j-stones[i]]+stones[i],dp[j]);
                }
            }
        }
        return tatol-2*dp[bag];
    }
}
